package cn.szabadsag.hrm.service.impl;

import cn.szabadsag.hrm.dto.SmsCodeLogDTO;
import cn.szabadsag.hrm.dto.SmsCodeDTO;
import cn.szabadsag.hrm.exception.Assert;
import cn.szabadsag.hrm.exception.BusinessException;
import cn.szabadsag.hrm.properties.VerifycodeProperties;
import cn.szabadsag.hrm.service.IVerifycodeService;
import cn.szabadsag.hrm.util.SendMsgUtils;
import cn.szabadsag.hrm.util.StrUtils;
import cn.szabadsag.hrm.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author yangcong
 * @date 2022年04月13日 17:00
 * @since
 */
@Service
@Slf4j
public class VerifycodeServiceImpl implements IVerifycodeService {

    //  导入此Redis可避免手动序列化实体类
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;


    //@Autowired
    //private SmscodeLogMapper smscodeLogMapper;

    @Autowired
    private VerifycodeProperties verifycodeProperties;

    /**
     * 创建图片验证码
     * @param key   前端生成并存储在localStorage中的UUID
     * @return
     */
    @Override
    public String createImageCode(String key) {
        //  1.参数判断(校验)
        Assert.assertNotEmpty(key,"非法请求！");
        //  2.条件判断
        //  3.生成6位验证码
        String imageCode = StrUtils.getComplexRandomString(verifycodeProperties.getVerifyCodeLen());
        //  4.将验证码存储到Redis中
        redisTemplate.opsForValue().set(key, imageCode, verifycodeProperties.getValueLifecycle(), TimeUnit.MINUTES);
        //  5.生成Base64图片验证码
        String base64 = null;
        try {
            base64 = VerifyCodeUtils.verifyCode(verifycodeProperties.getHeight(), verifycodeProperties.getWidth(), imageCode);
            return base64;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 发送手机验证码
     * @param dto 待校验参数(手机号、图片验证码、图片验证码的key)
     * @return
     */
    @Override
    public void sendSmsCode(SmsCodeDTO dto) {
        //  1.参数校验 使用Bean Validation-->JSR303参数校验@Valid
        String imageCode = dto.getImageCode();
        String imageCodeKey = dto.getImageCodeKey();
        String mobile = dto.getMobile();
        //  1.1 校验图片验证码与Redis中的是否一致
        String imageCodeInRedis = (String)redisTemplate.opsForValue().get(imageCodeKey);
        Assert.assertNotEmpty(imageCodeInRedis,"无效图片验证码或者图片验证码已过期！");
        if (!imageCodeInRedis.equalsIgnoreCase(imageCode)){
            throw new BusinessException("无效图片验证码或者图片验证码已过期！");
        }
        //  2.尝试获取上一次存储在redis中的手机验证码
        String smsCodeKey = "sms:" + mobile;
        SmsCodeLogDTO smsCodeInRedis = (SmsCodeLogDTO)redisTemplate.opsForValue().get("sms:" + mobile);
        String smsCode = null;
        Date now = new Date();
        if (smsCodeInRedis != null){
            //  2.1如果有，校验是否过期，
            if ((now.getTime() - smsCodeInRedis.getDate())/verifycodeProperties.getOneSecond() < verifycodeProperties.getOneMinute()){
                throw new BusinessException("发送过于频繁，请稍后再试！！！");
            }
            //  没有重发时间就将上一次的验证码发送给用户
            smsCode = smsCodeInRedis.getSmsCode();
        }else {
            //  2.2如果没有，就生成一个验证码并且存储到Redis中，然后发送给用户
            smsCode = StrUtils.getRandomString(verifycodeProperties.getVerifyCodeLen());
        }
        //  手机号:场景 验证码:时间戳
        SmsCodeLogDTO smsCodeLogDTO = new SmsCodeLogDTO(smsCode, now.getTime());
        redisTemplate.opsForValue().set(smsCodeKey, smsCodeLogDTO, verifycodeProperties.getValueLifecycle(), TimeUnit.MINUTES);
        //  3.调用网关短信，发送短信
        //SendMsgUtils.sendCode(mobile, smsCode);
        log.info("手机验证码：" + smsCode);
        //  4.数据库存储验证码发送记录
        /*SmscodeLog smscodeLog = new SmscodeLog();

        smscodeLog.setCreateTime(new Date().getTime());
        //  手机号
        smscodeLog.setPhone(mobile);
        //  验证码
        smscodeLog.setSmsCode(smsCode);
        //  类型1表示网建短信
        smscodeLog.setType(verifycodeProperties.getType_sms());
        //  状态1表示发送成功
        smscodeLog.setState(verifycodeProperties.getState_value());
        smscodeLogMapper.insert(smscodeLog);*/
    }























}
